package com.dyava.commons.lock.local;

import com.dyava.commons.lock.KeyLockException;
import com.dyava.commons.lock.KeyLockPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;

public class LocalKeyLockPool extends KeyLockPool {
    static Logger log = LoggerFactory.getLogger(LocalKeyLockPool.class);

    ConcurrentHashMap<String, ReentrantLock> lockMap = new ConcurrentHashMap<>();

    ExecutorService singleThreadPool = new ThreadPoolExecutor(1, 1,
            0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), (r) ->new Thread(r,"thread-keylock-local"));


    ReentrantLock obtainLock(String key){
        try {
            return CompletableFuture.supplyAsync(()->{
                ReentrantLock lock = lockMap.get(key);
                if(lock==null){
                    log.trace("{} -> 获得锁资源 新建锁资源",key);
                    lock = new ReentrantLock();
                    lockMap.put(key,lock);
                }else{
                    log.trace("{} -> 获得锁资源 原有锁资源",key);
                }
                return lock;
            },singleThreadPool).get();
        } catch (Exception e) {
            throw new KeyLockException(e);
        }
    }

    void cleanLock(String key){
        try {
            CompletableFuture.runAsync(()->{
                ReentrantLock lock = lockMap.get(key);
                if(lock!=null){
                    log.trace("{} -> 清除锁资源 原有锁资源",key);
                    if(lock.isLocked() || lock.hasQueuedThreads()){
                        log.trace("{} -> 清除锁资源 map保留",key);
                    }else{
                        log.trace("{} -> 清除锁资源 map剔除",key);
                        lockMap.remove(key);
                    }
                }else{
                    log.trace("{} -> 清除锁资源 不存在",key);
                }
            },singleThreadPool).get();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    void tryReleaseLock(LocalKeyLock localKeyLock){
        cleanLock(localKeyLock.getKey());
    }


    @Override
    public LocalKeyLock createLock(String key){
        ReentrantLock reentrantLock = obtainLock(key);
        LocalKeyLock localKeyLock = new LocalKeyLock(this,key,reentrantLock);
        return localKeyLock;
    }


}
